package cn.xn.hrms.domain.service.impl;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

import javax.annotation.Resource;

import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;

import cn.xn.hrms.api.dto.res.UserDTO;
import cn.xn.hrms.api.dto.res.UserRoleDTO;
import cn.xn.hrms.api.dto.req.UserReqDTO;
import cn.xn.hrms.api.dto.req.UserRoleReqDTO;
import cn.xn.hrms.domain.config.JWTUtils;
import cn.xn.hrms.domain.constants.Constant;
import cn.xn.hrms.domain.enums.ResultEnum;
import cn.xn.hrms.domain.exception.BaseException;
import cn.xn.hrms.domain.service.UserService;
import cn.xn.hrms.domain.utils.RedisUtils;
import cn.xn.hrms.infrastructure.dao.UserDao;
import cn.xn.hrms.infrastructure.dao.UserRoleDao;
import cn.xn.hrms.infrastructure.dataobject.UserDO;

/**
 * @author ysz
 */
@Service
public class UserServiceImpl implements UserService {

    @Resource
    private UserDao userDao;

    @Resource
    private UserRoleDao userRoleDao;

    @Resource
    private RedisUtils redisUtils;

    @Override
    public UserDTO findByUsername(String username) {
        UserDTO userDTO = userDao.selectByUsername(username);
        if (ObjectUtils.isEmpty(userDTO)) {
            throw new BaseException(ResultEnum.USER_NOT_EXIST);
        }
        return userDTO;
    }

    @Override
    public UserDTO find(int id) {
        UserDTO userDTO = userDao.selectByPrimaryKey(id);
        if (ObjectUtils.isEmpty(userDTO)) {
            throw new BaseException(ResultEnum.USER_NOT_EXIST);
        }
        return userDTO;
    }

    @Override
    public PageInfo<UserDO> findList(int pageNum, int pageSize, String name) {
        PageHelper.startPage(pageNum, pageSize);
        List<UserDO> findUserList = userDao.findAll(name);
        if (!CollectionUtils.isEmpty(findUserList)) {
            for (UserDO userDO : findUserList) {
                List<UserRoleDTO> userRoleList = userRoleDao.findAllByUserId(Long.valueOf(userDO.getUserId()));
                if (!CollectionUtils.isEmpty(userRoleList)) {
                    String roleNameStr =
                            userRoleList.stream().map(UserRoleDTO::getRoleDesc).collect(Collectors.joining(";"));
                    userDO.setRoleDesc(roleNameStr);

                }
            }
        }

        return new PageInfo<>(findUserList);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void deleteByIdIn(Collection<Integer> idList) {
        userDao.updateIsDeletedByIdIn(1, idList);
        // 删除用户角色映射
        userRoleDao.updateIsDeletedByUserIdIn(1, idList);
    }

    @Override
    public void insert(UserDTO userDTO) {

        // 校验用户名已存在
        UserDTO findUserDTO = userDao.selectByUsername(userDTO.getUsername());
        if (null != findUserDTO) {
            throw new BaseException(ResultEnum.USER_NAME_EXISTS);
        }
        userDao.insertSelective(userDTO);
    }

    @Override
    public void updateById(UserDTO userDTO) {
        userDao.updateByPrimaryKeySelective(userDTO);
    }

    @Override
    public void updatePassword(String oldPassword, String newPassword) {

        UserDTO loginUserDTO = (UserDTO) SecurityUtils.getSubject().getPrincipal();
        // 验证用户存在
        UserDTO findUserDTO = userDao.selectByUsername(loginUserDTO.getUsername());
        if (null == findUserDTO) {
            throw new BaseException(ResultEnum.USER_NOT_EXIST);
        }
        // 验证旧密码正确
        String pwd = new Md5Hash(oldPassword, findUserDTO.getSalt(), 100).toHex();
        if (!StringUtils.equals(findUserDTO.getPassword(), pwd)) {
            throw new BaseException(ResultEnum.OLD_PASSWORD_ERROR);
        }
        String salt = JWTUtils.getSalt();
        String password = new Md5Hash(newPassword, salt, 100).toHex();
        findUserDTO.setPassword(password);
        findUserDTO.setSalt(salt);
        userDao.updateByPrimaryKeySelective(findUserDTO);
    }

    @Override
    public void saveRoles(UserRoleReqDTO userRoleReqDTO) {

        UserDTO findUserDTO = userDao.selectByPrimaryKey(userRoleReqDTO.getUserId());
        if (null == findUserDTO) {
            throw new BaseException(ResultEnum.USER_NOT_EXIST);
        }
        // 删除已存在角色
        userRoleDao.updateIsDeletedByUserIdIn(1, Arrays.asList(userRoleReqDTO.getUserId()));
        List saveList = new ArrayList(userRoleReqDTO.getRoleIds().size());
        for (Long roleId : userRoleReqDTO.getRoleIds()) {
            UserRoleDTO userRoleDTO = new UserRoleDTO();
            userRoleDTO.setUserId(Long.valueOf(String.valueOf(userRoleReqDTO.getUserId())));
            userRoleDTO.setRoleId(roleId);
            saveList.add(userRoleDTO);
        }

        if (!CollectionUtils.isEmpty(saveList)) {
            userRoleDao.insertList(saveList);
        }
    }

    @Override
    public List<UserRoleDTO> getUserRoles(Long userId) {

        return userRoleDao.findAllByUserId(userId);
    }

    @Override
    public String userLogin(UserReqDTO userReqDTO) {

        String timestamp = userReqDTO.getTimestamp();
        // 校验验证码
        if (ObjectUtils.isEmpty(timestamp) || ObjectUtils.isEmpty(userReqDTO.getCode())) {
            throw new BaseException(ResultEnum.CODE_NOT_EXIST);
        }
        String redisKey = Constant.VERIFICATION_CODE_KEY_PREFIX + userReqDTO.getTimestamp();
        String verifyCode = redisUtils.getString(redisKey);
        if (StringUtils.isBlank(verifyCode)) {
            throw new BaseException(ResultEnum.CODE_INVALID);
        }
        // 忽略大小写
        if (!verifyCode.equalsIgnoreCase(userReqDTO.getCode())) {
            throw new BaseException(ResultEnum.CODE_FAIL);
        }

        String username = userReqDTO.getUsername();
        String password = userReqDTO.getPassword();
        // 校验用户名
        UserDTO us = findByUsername(username);
        String salt = us.getSalt();
        Md5Hash md5Hash = new Md5Hash(password, salt, 100);
        // 校验登录密码
        if (!StringUtils.equals(us.getPassword(), md5Hash.toHex())) {
            throw new BaseException(ResultEnum.PASSWORD_ERROR);
        }

        //生成token
        String token = JWTUtils.sign(username, md5Hash.toHex());
        //执行登入：登录接口放行，不做鉴权
        //SecurityUtils.getSubject().login(new JWTToken(token));
        // 当前登录信息放入缓存
        redisUtils.saveString(username, token, null);

        return token;
    }

    @Override
    public void update(Integer id, UserReqDTO us) {
        UserDTO userDTO = new UserDTO();
        BeanUtils.copyProperties(us, userDTO);
        if (ObjectUtils.isEmpty(us.getPassword())) {
            userDTO.setPassword(null);
        } else {
            String salt = JWTUtils.getSalt();
            String password = new Md5Hash(us.getPassword(), salt, 100).toHex();
            userDTO.setPassword(password);
            userDTO.setSalt(salt);
        }
        userDTO.setUserId(id);
        userDao.updateByPrimaryKeySelective(userDTO);

    }

    @Override
    public void create(UserReqDTO us) {
        String salt = JWTUtils.getSalt();
        String password = new Md5Hash(us.getPassword(), salt, 100).toHex();
        UserDTO userDTO = new UserDTO();
        BeanUtils.copyProperties(us, userDTO);
        userDTO.setSalt(salt);
        userDTO.setPassword(password);
        insert(userDTO);
    }
}
